(import
  (except (rnrs base) let-values map error)
  (only (guile) lambda* λ command-line string-null? string-count)
  ;; list procs
  (srfi srfi-1)
  ;; hash tables
  (srfi srfi-69)
  (fileio))


(define concat-lines
  (lambda* (lines #:key (separator-test string-null?) (inserted-separator ":"))
    (let next-line ([remaining-lines lines] [combined-line ""])
      (cond
       [(null? remaining-lines)
        (list (string-trim-both combined-line))]
       [else
        (let ([cur-line (first remaining-lines)])
          (cond
           ;; The passport-separator finishes an entry in
           ;; the lines. We cons the single passport data
           ;; onto the recursion and start collecting data
           ;; for the next single passport.
           [(separator-test cur-line)
            (cons (string-trim-both combined-line)
                  (next-line (cdr remaining-lines) ""))]
           ;; If more data for a single passport follows, we
           ;; append it onto the single passport data and
           ;; look at the next line.
           [else
            (next-line (cdr remaining-lines)
                       (string-append combined-line
                                      (if (string-null? combined-line)
                                          ""
                                          inserted-separator)
                                      cur-line))]))]))))


(define unique-chars
  (λ (str)
    (delete-duplicates (string->list str) char=?)))


(define process-passenger-group
  (λ (group-answers-string)
    (define group-answers (string-split group-answers-string #\:))
    (define unique-group-chars
      (filter (λ (char) (not (char=? char #\:)))
              (unique-chars group-answers-string)))
    (define num-group-passengers (length group-answers))

    ;; (simple-format (current-output-port) "unique chars of group: ~a\n" unique-group-chars)

    (fold (λ (group-chars-availability acc)
            (if (cdr group-chars-availability) (+ acc 1) acc))
          0
          (map (λ (char)
                 ;; (simple-format (current-output-port) "looking for ~a times char ~a in ~a\n" num-group-passengers char group-answers-string)
                 (cons char
                       ;; Is the number of occurences equal to the number of
                       ;; passengers in the group? NOTE: This does not work, if
                       ;; the input is not clean and any character appears
                       ;; multiple times for one passenger.
                       (= (string-count group-answers-string char) num-group-passengers)))
               unique-group-chars))))


(define main
  (λ (cmd-line-args)
    (let* ([lines (concat-lines (get-lines-from-file (second cmd-line-args)))])
      ;; (simple-format (current-output-port) "lines: ~a\n" lines)
      (apply + (map process-passenger-group lines)))))


(simple-format (current-output-port)
               "~a\n"
               (main (command-line)))
